
// ChildView.cpp : implementation of the CChildView class
//

#include "pch.h"
#include "framework.h"
#include "CameraPreview.h"
#include "ChildView.h"
#include "Preview.h"
#include "Utils.h"
#include "CCameraOcclusion.h"
#include "CChooseDevice.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

extern CPreview* g_pPreview;

// CChildView

CChildView::CChildView()
	:
#if SUPPORTTED_OCCLUSION_STATES
	m_pCameraOcclusion(NULL),
	m_pwszSymbolicLink(NULL),
	m_cchSymbolicLink(0)
#endif
{
}

CChildView::~CChildView()
{
	CloseDevice();
}


BEGIN_MESSAGE_MAP(CChildView, CWnd)
	ON_WM_PAINT()
	ON_WM_SIZE()
	ON_COMMAND(ID_FILE_CHOOSEDEVICE, &CChildView::OnFileChoosedevice)
	ON_COMMAND(ID_EDIT_PRIVACY, &CChildView::OnEditPrivacy)
END_MESSAGE_MAP()



// CChildView message handlers

HRESULT CChildView::SetDevice(IMFActivate* pActivate)
{
	HRESULT hr = S_OK;

	// Release the current instance of the player (if any).
	CloseDevice();

	if (SUCCEEDED(hr))
	{
		hr = pActivate->GetAllocatedString(
			MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK,
			&m_pwszSymbolicLink,
			&m_cchSymbolicLink
		);
	}

#if SUPPORTTED_OCCLUSION_STATES
	if (SUCCEEDED(hr))
	{
		m_pCameraOcclusion = new CCameraOcclusion();
		hr = m_pCameraOcclusion->CreateCameraOcclusionStateMonitor(m_pwszSymbolicLink);
		if (SUCCEEDED(hr))
		{
			auto states = m_pCameraOcclusion->GetSupporttedOcclusionStates();
			if (states > MFCameraOcclusionState_Open)
			{
				hr = m_pCameraOcclusion->StartOcclusionStateMoitor();
			}
			else
			{
				SafeRelease(&m_pCameraOcclusion);
				m_pCameraOcclusion = NULL;
			}
		}
	}
#endif

	// When the method completes, MFPlay will call OnMediaPlayerEvent
   // with the MFP_EVENT_TYPE_MEDIAITEM_CREATED event.

	if (FAILED(hr))
	{
		CloseDevice();
	}

	return hr;
}

HRESULT CChildView::CloseDevice()
{
	HRESULT hr = S_OK;

#if SUPPORTTED_OCCLUSION_STATES
	if (m_pCameraOcclusion)
	{
		m_pCameraOcclusion->StopOcclusionStateMonitor();
		m_pCameraOcclusion->Release();
		m_pCameraOcclusion = NULL;
	}
#endif

	CoTaskMemFree(m_pwszSymbolicLink);
	m_pwszSymbolicLink = NULL;

	m_cchSymbolicLink = 0;

	return hr;
}

BOOL CChildView::PreCreateWindow(CREATESTRUCT& cs)
{
	if (!CWnd::PreCreateWindow(cs))
		return FALSE;

	cs.dwExStyle |= WS_EX_CLIENTEDGE;
	cs.style &= ~WS_BORDER;
	cs.lpszClass = AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS,
		::LoadCursor(nullptr, IDC_ARROW), reinterpret_cast<HBRUSH>(COLOR_WINDOW + 1), nullptr);

	return TRUE;
}

void CChildView::OnPaint()
{
	CPaintDC dc(this); // device context for painting

	// TODO: Add your message handler code here
	if (g_pPreview && g_pPreview->HasVideo())
	{
		g_pPreview->UpdateVideo();
	}

	// Do not call CWnd::OnPaint() for painting messages
}

void CChildView::OnSize(UINT nType, int cx, int cy)
{
	__super::OnSize(nType, cx, cy);
	if (nType == SIZE_RESTORED)
	{
		if (g_pPreview)
		{
			// Resize the video to cover the entire client area.
			g_pPreview->UpdateVideo();
		}
	}
}

void CChildView::OnFileChoosedevice()
{
	// TODO: Add your command handler code here
	HRESULT hr = S_OK;
	ChooseDeviceParam param = { 0 };

	IMFAttributes* pAttributes = NULL;

	// Release the previous instance of the preview object, if any.
	if (g_pPreview)
	{
		g_pPreview->CloseDevice();
		SafeRelease(&g_pPreview);
	}

	// Create a new instance of the preview object.
	hr = CPreview::CreateInstance(GetSafeHwnd(), &g_pPreview);

	// Create an attribute store to specify the enumeration parameters.

	if (SUCCEEDED(hr))
	{
		hr = MFCreateAttributes(&pAttributes, 1);
	}

	// Ask for source type = video capture devices

	if (SUCCEEDED(hr))
	{
		hr = pAttributes->SetGUID(
			MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE,
			MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID
		);
	}

	// Enumerate devices.

	if (SUCCEEDED(hr))
	{
		hr = MFEnumDeviceSources(pAttributes, &param.ppDevices, &param.count);
	}

	if (SUCCEEDED(hr))
	{
		// Ask the user to select one.
		CChooseDeviceDlg dlg;
		dlg.SetDeviceParam(&param);

		if ((dlg.DoModal() == IDOK) && (param.selection != (UINT32)-1))
		{
			UINT iDevice = param.selection;

			if (iDevice >= param.count)
			{
				hr = E_UNEXPECTED;
			}
			else
			{
				// Give this source to the CPreview object for preview.
				hr = g_pPreview->SetDevice(param.ppDevices[iDevice]);
			}
		}
	}

	SafeRelease(&pAttributes);

	for (DWORD i = 0; i < param.count; i++)
	{
		SafeRelease(&param.ppDevices[i]);
	}
	CoTaskMemFree(param.ppDevices);

	if (FAILED(hr))
	{
		ShowErrorMessage(GetComExceptionMessage(hr), hr);
	}
}


void CChildView::OnEditPrivacy()
{
	// TODO: Add your command handler code here
	HRESULT hr = S_OK;
	ChooseDeviceParam param = { 0 };

	IMFAttributes* pAttributes = NULL;

	// Create an attribute store to specify the enumeration parameters.

	if (SUCCEEDED(hr))
	{
		hr = MFCreateAttributes(&pAttributes, 1);
	}

	// Ask for source type = video capture devices

	if (SUCCEEDED(hr))
	{
		hr = pAttributes->SetGUID(
			MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE,
			MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID
		);
	}

	// Enumerate devices.

	if (SUCCEEDED(hr))
	{
		hr = MFEnumDeviceSources(pAttributes, &param.ppDevices, &param.count);
	}

	if (SUCCEEDED(hr))
	{
		// Ask the user to select one.
		CChooseDeviceDlg dlg;
		dlg.SetDeviceParam(&param);

		if ((dlg.DoModal() == IDOK) && (param.selection != (UINT32)-1))
		{
			UINT iDevice = param.selection;

			if (iDevice >= param.count)
			{
				hr = E_UNEXPECTED;
			}
			else
			{
				// Give this source to the CPreview object for preview.
				//hr = g_pPreview->SetDevice(param.ppDevices[iDevice]);
				hr = SetDevice(param.ppDevices[iDevice]);
			}
		}
	}

	SafeRelease(&pAttributes);

	for (DWORD i = 0; i < param.count; i++)
	{
		SafeRelease(&param.ppDevices[i]);
	}
	CoTaskMemFree(param.ppDevices);

	if (FAILED(hr))
	{
		ShowErrorMessage(GetComExceptionMessage(hr), hr);
	}
}
